﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YenAlgorithm;

namespace NetworkSimulator
{
    public class RRATE : Routing
    {
        //contain k shortest paths of each i-e pair
        List<List<Path>> kShortestPaths = new List<List<Path>>();

        //Contain x value
        List<List<int>> xlist = new List<List<int>>();

        //moderation parameters
        double k1, k2;

        //the number of shotest paths
        int k;


        public RRATE()
            : base()
        {
            k1 = 1;
            k2 = 1;
        }

        public RRATE(double k1, double k2)
            : base()
        {
            this.k1 = k1;
            this.k2 = k2;
        }



        public override Path getPath(Request req)
        {
            kShortestPaths = offline_RRATE.kShortestPaths;
            xlist = offline_RRATE.xlist;

            if (req.Source == 0 && req.Destination == 0)
                return null;

            //Get index of i-e
            int p = 0;
            Path result = new Path();

            foreach (var pair in ieList.IngressEgressList)
            {
                if (pair.Ingress.Id == req.Source && pair.Egress.Id == req.Destination) break;
                else p++;
            }

            k = kShortestPaths[p].Count;

            bool flag = false;

            foreach (var xvalue in xlist[p])
                if (xvalue >= offline_RRATE.N)
                {
                    flag = true;
                    break;
                }

            //Learning stage, if quantity of routed request in requestlist <= N
            #region
            if (!flag)
            {

                //this.Renew();

                List<Link> criticalLinks = new List<Link>();

                //Find critical-link set
                criticalLinks = getCriticalLinks(ieList[p].Ingress, ieList[p].Egress);

                //Go to each path in i-e pair to count critical link and find max Residual bw
                for (int i = 0; i < k; i++)
                {
                    int c_link_num = 0;

                    double max_residualbw = 0;

                    foreach (var link in kShortestPaths[p][i].Links)
                    {
                        foreach (var clink in criticalLinks)
                            if (link.Source.Id == clink.Source.Id && link.Destination.Id == clink.Destination.Id)
                                c_link_num++;

                        //Find max residual bw of one path
                        if (link.ResidualBandwidth - req.Bandwidth > max_residualbw)
                        {
                            max_residualbw = link.ResidualBandwidth - req.Bandwidth;
                        }
                    }

                    //Calculate Cost of path
                    if (max_residualbw > 0)
                        kShortestPaths[p][i].cost = (k1 * c_link_num + k2 / max_residualbw);
                    else kShortestPaths[p][i].cost = Double.MaxValue;
                }


                //Sort paths in increasing order of cost
                Path p_tmp = new Path();
                int x_tmp;

                for (int i = 0; i < k - 1; i++)
                    for (int j = i + 1; j < k; j++)
                        if (kShortestPaths[p][i].cost > kShortestPaths[p][j].cost)
                        {
                            //Swap position of k paths
                            p_tmp = kShortestPaths[p][i];
                            kShortestPaths[p][i] = kShortestPaths[p][j];
                            kShortestPaths[p][j] = p_tmp;

                            //Swap position of x value
                            x_tmp = xlist[p][i];
                            xlist[p][i] = xlist[p][j];
                            xlist[p][j] = x_tmp;
                        }

                //Choose suitable path
                for (int i = 0; i < k; i++)
                {
                    Path tmp = new Path();

                    foreach (var linkofpath in kShortestPaths[p][i].Links)
                        foreach (var node in map.Nodes)
                            foreach (var link in node.Links)
                                if (link.Source == linkofpath.Source && link.Destination == linkofpath.Destination)
                                {
                                    tmp.Links.Add(link);
                                }
                    if (tmp.ResidualBandwidth >= req.Bandwidth)
                    {
                        xlist[p][i]++;
                        result = tmp;
                        break;
                    }
                }

            }
            #endregion


            //Post-learning stage
            #region
            else
            {
                //Sort x-value
                for (int i = 0; i < k - 1; i++)
                    for (int j = i + 1; j < k; j++)
                        //if (kShortestPaths[p][i].cost > kShortestPaths[p][j].cost)
                        if (xlist[p][i] < xlist[p][j])
                        {
                            //Swap position of k paths
                            Path p_tmp = kShortestPaths[p][i];
                            kShortestPaths[p][i] = kShortestPaths[p][j];
                            kShortestPaths[p][j] = p_tmp;

                            //Swap position of x value
                            int x_tmp = xlist[p][i];
                            xlist[p][i] = xlist[p][j];
                            xlist[p][j] = x_tmp;
                        }

                //Choose suitable path
                for (int i = 0; i < k; i++)
                {
                    Path tmp = new Path();

                    foreach (var linkofpath in kShortestPaths[p][i].Links)
                        foreach (var node in map.Nodes)
                            foreach (var link in node.Links)
                                if (link.Source == linkofpath.Source && link.Destination == linkofpath.Destination)
                                    tmp.Links.Add(link);

                    if (tmp.ResidualBandwidth >= req.Bandwidth)
                    {
                        xlist[p][i]++;
                        result = tmp;
                        break;
                    }
                }

            }
            #endregion

            offline_RRATE.xlist = xlist;
            offline_RRATE.kShortestPaths = kShortestPaths;

            return result;
        }


    }

}
